package main

import (
	"time"

	"gitee.com/ameise84/e3dcs"
	"gitee.com/ameise84/e3dcs/internal/discov"
	"gitee.com/ameise84/e3dcs/internal/log"
	"gitee.com/ameise84/e3dcs/internal/message"
	"gitee.com/ameise84/e3net"
	"gitee.com/ameise84/e3utils/str_conv"
	"gitee.com/ameise84/e3utils/sys"
)

type NetServer struct {
}

type NetContext struct {
	id        string
	sendCount uint64
	recvCount uint64
	a         e3dcs.Behavior
	c         e3net.Conn
}

func (ts *NetContext) OnResponse(rsp *message.Message) {
	log.GetLogger().Info("OnResponse").Object(rsp).Println()
	ts.c.SendSync(rsp.GetBody())
}

func (ts *NetContext) OnPush(protoc string, body []byte) {
	log.GetLogger().Info("OnPush").Println()
	ts.c.SendSync(body)
}

func (ts *NetContext) OnRecv(conn e3net.Conn, bs []byte) ([]byte, error) {
	log.GetLogger().Debug("net context on recv").Str("bs", string(bs)).Println()
	ts.recvCount++
	msg := message.TakeMessage()
	msg.SetKind(message.MsgRaw)
	msg.SetMsg("hello", bs)
	msg.SetID(ts.recvCount)
	msg.SetToActor(conn.Tag(), "", ts.id)
	msg.SetSrvID("s2")
	msg.SetRspHandler(ts)
	e3dcs.Post(msg)
	return nil, nil
}

func (ts *NetServer) OnNewConnect(tag e3net.Tag, conn e3net.Conn) e3net.ConnContext {
	log.GetLogger().Trace("OnNewConnect").Println()
	ctx := &NetContext{id: str_conv.ToString(conn.ID())}
	a, _ := gActorServer.StartLocalActor(ctx.id)
	ctx.a = a
	ctx.c = conn
	gActorServer.BindNetContext(a, ctx)
	a.AttachPushHandler("s2", a.ClerkID())
	return ctx
}

func (ts *NetServer) OnClosedConnect(ctx e3net.ConnContext) {
	log.GetLogger().Trace("OnClosedConnect").Println()
	raw := ctx.(*NetContext)
	gActorServer.UnBindNetContext(raw.a)
	gActorServer.StopLocalActor(raw.id)
}

var gActorServer e3dcs.NetService

type ServiceAFactory struct {
}

func (ts *ServiceAFactory) TakeActor() e3dcs.ActorAdapter {
	return &ServiceA{}
}

func (ts *ServiceAFactory) FreeActor(actor e3dcs.ActorAdapter) {

}

func (ts *ServiceAFactory) OnBroadcast(request message.Request) {
	//TODO implement me
	panic("implement me")
}

type ServiceA struct {
}

func (ts *ServiceA) Load(cid string, actor e3dcs.Behavior) error {
	log.GetLogger().Trace("Load").Object(actor).Println()
	return nil
}

func (ts *ServiceA) Unload(bool) {
	return
}

func (ts *ServiceA) OnTimer(kind uint16, id uint32, now time.Time, ctx e3dcs.TimerContext) bool {
	return true
}

func (ts *ServiceA) OnRecvMsg(actor e3dcs.Behavior, req message.Request) bool {
	log.GetLogger().Info("OnRecvMsg").Object(actor).Object(req).Println()
	rsp, err := actor.Call("s2", actor.ClerkID(), "x", req.GetBody())
	if err != nil {
		req.ResponseMsg("s1", []byte("err"))
	} else {
		req.ResponseMsg("s1", rsp.GetBody())
	}
	return true
}

func main() {
	var err error
	if gActorServer, err = e3dcs.RegisterNetService("s1", &ServiceAFactory{}, 64); err != nil {
		panic(err)
	}
	err = e3dcs.Start(e3dcs.DefaultDcsOptions())
	if err != nil {
		panic(err)
		return
	}

	netSrv := e3net.NewTcpServer()
	_, err = netSrv.AddAcceptor(&NetServer{}, "s1", ":4554", false)
	if err != nil {
		panic(err)
	}
	err = netSrv.Start()
	if err != nil {
		panic(err)
	}
	sys.WaitKillSigint()
	e3dcs.Stop()
	discov.Stop()
}
